From 87ad4426dd72ea52f172bbb1512328d1467e6eab Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 31 Oct 2014 10:49:04 -0700 Subject: [PATCH] Implement the `links` manifest key This commit adds the `links` manifest key as a string of a C library which is being linked to. This is passed as an argument to the build command when not overridden. The implementation of overrides will come soon! --- src/cargo/core/manifest.rs | 10 +++- src/cargo/ops/cargo_rustc/custom_build.rs | 2 +- src/cargo/ops/cargo_rustc/links.rs | 37 ++++++++++++++ src/cargo/ops/cargo_rustc/mod.rs | 3 ++ src/cargo/util/toml.rs | 2 + tests/test_cargo_compile_custom_build.rs | 60 ++++++++++++++++++++++- 6 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 src/cargo/ops/cargo_rustc/links.rs diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 666790746..ca40de4c0 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -17,6 +17,7 @@ pub struct Manifest { target_dir: Path, doc_dir: Path, build: Vec, // TODO: deprecated, remove + links: Option, warnings: Vec, exclude: Vec, metadata: ManifestMetadata, @@ -328,7 +329,7 @@ impl hash::Hash for Profile { env: _, test: _, doctest: _, - + custom_build: _, } = *self; (opt_level, codegen_units, debug, rpath, for_host, dest, harness).hash(into) @@ -383,7 +384,7 @@ impl Show for Target { impl Manifest { pub fn new(summary: Summary, targets: Vec, target_dir: Path, doc_dir: Path, - build: Vec, exclude: Vec, + build: Vec, exclude: Vec, links: Option, metadata: ManifestMetadata) -> Manifest { Manifest { summary: summary, @@ -393,6 +394,7 @@ impl Manifest { build: build, // TODO: deprecated, remove warnings: Vec::new(), exclude: exclude, + links: links, metadata: metadata, } } @@ -433,6 +435,10 @@ impl Manifest { self.build.as_slice() } + pub fn get_links(&self) -> Option<&str> { + self.links.as_ref().map(|s| s.as_slice()) + } + pub fn add_warning(&mut self, s: String) { self.warnings.push(s) } diff --git a/src/cargo/ops/cargo_rustc/custom_build.rs b/src/cargo/ops/cargo_rustc/custom_build.rs index 1fb19f763..55c022327 100644 --- a/src/cargo/ops/cargo_rustc/custom_build.rs +++ b/src/cargo/ops/cargo_rustc/custom_build.rs @@ -94,7 +94,7 @@ pub fn prepare_execute_custom_build(pkg: &Package, target: &Target, let output = try!(p.exec_with_output().map_err(|mut e| { e.msg = format!("Failed to run custom build command for `{}`\n{}", pkg, e.msg); - e.mark_human() + e.concrete().mark_human() })); // parsing the output of the custom build script to check that it's correct diff --git a/src/cargo/ops/cargo_rustc/links.rs b/src/cargo/ops/cargo_rustc/links.rs new file mode 100644 index 000000000..dbb69528c --- /dev/null +++ b/src/cargo/ops/cargo_rustc/links.rs @@ -0,0 +1,37 @@ +use std::collections::HashMap; + +use core::PackageSet; +use util::{CargoResult, human}; + +// Returns a mapping of the root package plus its immediate dependencies to +// where the compiled libraries are all located. +pub fn validate(deps: &PackageSet) -> CargoResult<()> { + let mut map = HashMap::new(); + + for dep in deps.iter() { + let lib = match dep.get_manifest().get_links() { + Some(lib) => lib, + None => continue, + }; + match map.find(&lib) { + Some(previous) => { + return Err(human(format!("native library `{}` is being linked \ + to by more than one package, and \ + can only be linked to by one \ + package\n\n {}\n {}", + lib, previous, dep.get_package_id()))) + } + None => {} + } + if !dep.get_manifest().get_targets().iter().any(|t| { + t.get_profile().is_custom_build() + }) { + return Err(human(format!("package `{}` specifies that it links to \ + `{}` but does not have a custom build \ + script", dep.get_package_id(), lib))) + } + map.insert(lib, dep.get_package_id()); + } + + Ok(()) +} diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 65db067d4..4691fdc70 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -26,6 +26,7 @@ mod fingerprint; mod job; mod job_queue; mod layout; +mod links; #[deriving(PartialEq, Eq)] pub enum Kind { KindHost, KindTarget } @@ -83,6 +84,8 @@ pub fn compile_targets<'a>(env: &str, targets: &[&'a Target], pkg: &'a Package, debug!("compile_targets; targets={}; pkg={}; deps={}", targets, pkg, deps); + try!(links::validate(deps)); + let dest = uniq_target_dest(targets); let root = deps.iter().find(|p| p.get_package_id() == resolve.root()).unwrap(); let host_layout = Layout::new(root, None, dest); diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 82435718b..3c98df6df 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -252,6 +252,7 @@ pub struct TomlProject { version: TomlVersion, authors: Vec, build: Option, // TODO: `String` instead + links: Option, exclude: Option>, // package metadata @@ -514,6 +515,7 @@ impl TomlManifest { layout.root.join("doc"), old_build, exclude, + project.links.clone(), metadata); if used_deprecated_lib { manifest.add_warning(format!("the [[lib]] section has been \ diff --git a/tests/test_cargo_compile_custom_build.rs b/tests/test_cargo_compile_custom_build.rs index 9332dccb9..db4613abd 100644 --- a/tests/test_cargo_compile_custom_build.rs +++ b/tests/test_cargo_compile_custom_build.rs @@ -1,5 +1,3 @@ -use std::path; - use support::{project, execs}; use support::{COMPILING, RUNNING}; use hamcrest::{assert_that}; @@ -188,3 +186,61 @@ url = p.url(), ))); }) */ + +test!(links_no_build_cmd { + let p = project("foo") + .file("Cargo.toml", r#" + [project] + name = "foo" + version = "0.5.0" + authors = [] + links = "a" + "#) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("build"), + execs().with_status(101) + .with_stderr("\ +package `foo v0.5.0 (file://[..])` specifies that it links to `a` but does \ +not have a custom build script +")); +}) + + +test!(links_duplicates { + let p = project("foo") + .file("Cargo.toml", r#" + [project] + name = "foo" + version = "0.5.0" + authors = [] + links = "a" + build = "build.rs" + + [dependencies.a] + path = "a" + "#) + .file("src/lib.rs", "") + .file("build.rs", "") + .file("a/Cargo.toml", r#" + [project] + name = "a" + version = "0.5.0" + authors = [] + links = "a" + build = "build.rs" + "#) + .file("a/src/lib.rs", "") + .file("a/build.rs", ""); + + assert_that(p.cargo_process("build"), + execs().with_status(101) + .with_stderr("\ +native library `a` is being linked to by more than one package, and can only be \ +linked to by one package + + foo v0.5.0 (file://[..]) + a v0.5.0 (file://[..]) +")); +}) + -- 2.30.2